本次面试其实面的很简单,但是算法题做了两道,并且是视频面试,对我来说是一个全新的体验吧。基本上所有的问题都回答出来了,但是算法的最后一道题没有弄出来。因为是字节跳动的提前批,他们所说的学霸批,也没有抱太大的希望,就当过去玩一下了
秋招正式开始啦!
## 1、项目内容
项目内容中问到了关于登录鉴权的的问题。这里我回答了我参与的科协通用报名系统管理端的管理员单点登录方法。这个项目的STAR如下:
+ Situation:一个南理工科协开发的基于微信小程序的通用报名系统,用于简化传统报名过程中步骤繁杂、统计麻烦等问题。包括一个报名端(微信小程序)和一个管理端(一页式网站)
+ Task:我在本项目中负责后端业务逻辑的开发、数据库表结构的设计和实现、服务器的配置和部署。除此之外,还负责与前端开发组进行API的管理、联调等工作。
+ Action:在本项目中,最大的一个特点就是“通用”。由于要具有通用性,我在表结构的设计时将报名表的结构和他的类别进行解耦,降低了表的数量,提高了通用性。具体地,报名项包括好几个类别,但是他们都存在同一个表下,通过type字段进行区分。而报名者信息将不是与报名绑定,而是与报名项绑定。这样可以很方便地对报名信息的唯一性和必填性进行检查。但是这样带来的缺点就是业务逻辑更加复杂,并且数据库直接可读性较差。后端框架选用了Tomcat + SpringMVC + SpringData + MySQL,请求API使用RESTFul风格,使用github进行版本控制,使用eolinker进行API文档管理。
+ Result:在7天内完成了软件后端从无到有的开发,并且目前(2019年4月7日)已经迭代了三个版本(V1.1)
其中,单点登录的实现方法是通过服务器端的Session的鉴别来实现单点登录的。
## 2、Cookies和Session的区别
因为项目里问到了Session,面试官就顺带问了Session和Cookies的区别。这里我回答的还算可以。整理一下,他们两个的异同如下:
+ 相同点:都可以存储和访问有关的数据,都有过期时间,都可以根据客户端的来进行创建或不创建
+ 不同点:
+ Session:中文名为会话信息,创建在Web服务器上。当超过过期时间后Session将会被销毁,里面存储的数据也不可访问。**注意,用户关闭了网页或客户端并不意味着销毁这次会话所创建的Session**
+ Cookies:位于用户的计算机上,用来维护用户计算机中的信息,直到过期或用户手动删除。
## 3、HTTP和TCP的关系
这里回答的有瑕疵。应该明确的一点是:**HTTP是建立在TCP上的一种传输协议,是基于TCP的一种应用。**
TCP位于传输层,负责建立服务器和客户机之间的通讯链路,而HTTP则负责基于这个链路之上对所需要的数据进行传输。
## 4、用户输入URL之后会发生什么
这个在学习tomcat的时候有顺带学习过。这里详细列出:
+ 浏览器先查询本机是否有主域名对应的映射IP,如果有则直接路由至该IP,否则访问DNS服务器,获取域名对应的IP地址,然后与IP地址对应的主机(Web服务器)建立TCP连接
+ 浏览器发出HTTP请求(主机名后面的地址为HTTP请求地址)
+ Web服务器收到HTTP请求后解析HTTP请求并返回相应的文件数据
+ 浏览器收到HTTP响应并解析响应,并在窗口渲染超文本
## 5、生产者和消费者模型
通过消息队列来进行生产者和消费者的同步。**反正至始至终都是一个原则,要有生产者生产了产品,消费者才能进行消费。**
## 6、线程和进程的区别
老生常谈,之前有写到过:
> [腾讯 WXG 零面总结](http://cong-onion.cn/archives/tencent-interview-wxg-1)
进程:进程是具有独立功能的程序在某个数据集合上的一次执行过程。进程是系统进行资源分配和调度的一个独立单位。
线程:线程是进程内的一个执行实体或者执行单元,是比进程更小的、能够独立运行的基本单位。
区别:
不同进程的地址空间相互独立,而同一进程内部的线程共享同一地址空间。一个进程内部的线程对另外一个进程是不可见的。
创建进程和撤销进程,系统都要为之分配或者回收资源,操作系统的开销远大于创建和撤销线程。
## 7、用过哪些常见的HTTP header
这里我是真滴没有怎么用过,只说了个Content-Type。
具体的可以学习一下这篇文章:
> [常见的HTTP Header](https://www.cnblogs.com/hnhycnlc888/p/9607632.html)
简单来说,有这么几个header:
+ Content-Type:指定请求和响应的内容类型,如果未指定即为text/html
+ Content-Length:用于指定请求或相应的内容长度
+ Accept-Encoding、Content-Encoding:压缩算法
+ Vary:代理缓存
+ connection: keep-alive:长连接
+ Location: http://www.baidu.com:重定向
## 8、算法:寻找翻转数组的中位数
题目如下:
有一个有序数组如:1,2,3,4,5,6,7。随机选一个点比如5反转变成:5,6,7,1,2,3,4。对于上面翻转后的数组,求它的中位数。
是剑指offer中一道经典的题目。实际上是一个变形的二分查找题。具体的思路就是,因为在翻转前数组是有序的,那么找到当前翻转后的数组的最小的那个数,再加上当前数组长度的一半(要注意处理数组越界)那么就可以得到中位数了(如果是偶数个的话,返回第一个中位数即可)
题解如下:
```java
// 是直接从当时写的代码上复制下来的,不保证编译通过哈
public class Main {
public static void main(String[] args) {
System.out.println(middle(new int[]{5, 6, 7, 1, 2, 3, 4}, 0, 6));
}
private static int middle(int[] array, int start, int end){
int mid = (start + end) / 2;
if(start < end){
if(array[mid] > array[end]){
middle(array, mid, end);
// 当初这里写了mid + 1,下面写了mid - 1,其实是没有必要的,如果写上的话会导致跨过一个数字
}
else middle(array, start, mid);
}
else{
return array[((start + array.length()) / 2) % array.length()];
}
}
}
```
## 9、算法:寻找单向链表的环的位置
题目如下:
判断单向链表是否有环,如果有环,找出环的位置。
也是剑指offer的题目(题目23)。这里我采取的是差速法,就是快慢指针。一开始只用判断链表是否有环,后面加上了寻找环的位置。
最后我只写出了判断是否有环的代码,而入口最后没有想出来。
题解如下:
```java
// 是直接从当时写的代码上复制下来的,不保证编译通过哈
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
private static int criList(Node node){
if(node == null) return false;
Node ptr1 = node;
Node ptr2 = node;
while(ptr2 != null && node.next != null){
ptr1 = ptr1.next;
for(int i = 0; i < 2; i++){
if(ptr1 == ptr2) return true;
if(ptr2 == null) return -1;
ptr2 = ptr2.next;
}
}
return false;
}
}
```
关于怎么找环的入口,剑指offer里面说的很清楚了。
如果链表存在环,那么快慢指针相遇就一定在环中。当他们相遇之后,从相遇的节点出发,一边继续向前一边计数,当再次回到这个相遇的节点的时候,那么计数的值就是环中节点的个数了。
得到了环中节点的个数之后,重新将两个指针初始化回头结点,然后将其中一个指针向前移动环中节点的个数个节点。然后他们以相同的速率向前移动,当他们相遇时,那个节点就是链表的入口节点。
具体代码如下:
```java
// 这里只贴出了寻找环入口的代码
private static ListNode entryNodeOfLoop(ListNode head) {
ListNode meetingNode = meetingNode(head);
if (meetingNode == null) return null;
int nodesInLoop = 1;
// 计算环内节点个数
ListNode node1 = meetingNode;
while (node1.next != meetingNode) {
node1 = node1.next;
nodesInLoop++;
}
// 寻找入口
// 先将p1向前移动,次数为环内节点的数目
node1 = head;
for (int i = 0; i < nodesInLoop; i++) {
node1 = node1.next;
}
// p1和p2一起移动,当他们相遇时,p1刚好走完一圈(p1和p2的距离就是环内节点的个数),相遇的节点就是环入口
ListNode node2 = head;
while (node1 != node2) {
node1 = node1.next;
node2 = node2.next;
}
return node1;
}
【秋招面经】字节跳动-秋招提前批-深圳后端工程师 一面面经